package com.easy.frame.servers.sys.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.easy.frame.base.api.pojo.PageDTO;
import com.easy.frame.base.api.pojo.PageVO;
import com.easy.frame.base.basic.ServiceResponse;
import com.easy.frame.base.basic.enums.ResponseCodeEnum;
import com.easy.frame.base.basic.exception.ServiceException;
import com.easy.frame.base.basic.util.AuthUtil;
import com.easy.frame.base.basic.util.DateUtils;
import com.easy.frame.base.service.mp.page.PageProxy;
import com.easy.frame.servers.sys.dto.SysProjectDTO;
import com.easy.frame.servers.sys.entity.SysProject;
import com.easy.frame.servers.sys.entity.SysProjectAuth;
import com.easy.frame.servers.sys.entity.SysProjectDetail;
import com.easy.frame.servers.sys.mapper.project.SysProjectAuthMapper;
import com.easy.frame.servers.sys.mapper.project.SysProjectDetailMapper;
import com.easy.frame.servers.sys.mapper.project.SysProjectMapper;
import com.easy.frame.servers.sys.service.SysProjectAuthService;
import com.easy.frame.servers.sys.service.SysProjectService;
import com.easy.frame.servers.sys.vo.SysProjectAuthVO;
import com.easy.frame.servers.sys.vo.SysProjectVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 项目表 服务实现类
 *
 * @author zzf
 * @since 2020-12-14
 */
@Slf4j
@Service
public class SysProjectServiceImpl extends ServiceImpl<SysProjectMapper, SysProject> implements SysProjectService {

    @Resource
    SysProjectAuthMapper sysProjectAuthMapper;
    @Resource
    SysProjectAuthService sysProjectAuthService;
    @Resource
    SysProjectDetailMapper sysProjectDetailMapper;

    @Override
    public PageVO<SysProjectVO> selectForPage(PageDTO<SysProjectDTO> pageDTO) {
        if (StrUtil.isEmpty(pageDTO.getSortName()) && StrUtil.isEmpty(pageDTO.getSortOrder())) {
            pageDTO.setSortName("CONVERT ( prod.city USING gbk ), CONVERT ( pro.`name` USING gbk )");
            pageDTO.setSortOrder("asc");
        }
        return PageProxy.proxy(baseMapper::selectForPage, pageDTO);
    }

    @Override
    public SysProjectVO getProjectVoById(Long id) {
        return baseMapper.getProjectVOById(id);
    }

    /**
     * 编辑保存项目表
     * 编辑保存保存校验规则： “城市+项目名称”唯一； 项目编码，整个系统唯一；必填校验；
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ServiceResponse<?> updateProjectVoById(SysProjectDTO entity) {
        int countN = baseMapper.checkProjectId(entity.getCity(), entity.getProName());
        int countC = baseMapper.checkProjectCode(entity.getProCode());
        SysProject project = baseMapper.selectById(entity.getId());
        if (countN > 1 || (countN > 0 && !entity.getProName().equals(project.getName()))) {
            throw new ServiceException("新增项目名【" + entity.getProName() + "】已存在，请修改后提交");
        }
        if (countC > 1 || (countC > 0 && !entity.getProCode().equals(project.getCode()))) {
            throw new ServiceException("新增项目code【" + entity.getProCode() + "】已存在，请修改后提交");
        }
        SysProject sysProject = packSysProject(entity);
        baseMapper.updateByProjectId(sysProject);
        log.info("插入SysProjectVO中sysProject：" + sysProject);
        SysProjectDetail sysProjectDetail = packSysProjectDetail(entity);
        sysProjectDetailMapper.updateByProjectId(sysProjectDetail);
        log.info("插入SysProjectVO中sysProjectDetail：" + sysProjectDetail);

        return new ServiceResponse<>(entity, ResponseCodeEnum.SUCCESS);
    }

    /**
     * 新增项目表
     * 保存校验规则： “城市+项目名称”唯一； 项目编码，整个系统唯一；必填校验；
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ServiceResponse<?> saveSysProjectVO(SysProjectDTO entity) {
        //保存校验
        int countN = baseMapper.checkProjectId(entity.getCity(), entity.getProName());
        int countC = baseMapper.checkProjectCode(entity.getProCode());
        if (countN > 0) {
            throw new ServiceException("新增项目名【" + entity.getProName() + "】已存在，请修改后提交");
        }
        if (countC > 0) {
            throw new ServiceException("新增项目code【" + entity.getProCode() + "】已存在，请修改后提交");
        }
        SysProject packSysProject = packSysProject(entity);
        baseMapper.insert(packSysProject);

        Long projectId = packSysProject.getId();
        SysProjectDetail sysProjectDetail = packSysProjectDetail(entity);
        sysProjectDetail.setProjectId(projectId);
        sysProjectDetail.setBuildDate(entity.getBuildDate());
        sysProjectDetailMapper.insert(sysProjectDetail);
        return new ServiceResponse<>(entity, ResponseCodeEnum.SUCCESS);
    }

    @Override
    public SysProjectAuth selectForAuth(int projectId) {
        return sysProjectAuthMapper.selectById(projectId);
    }

    @Override
    public PageVO<SysProjectAuthVO> selectAuthForPage(PageDTO<SysProjectAuth> pageDTO) {
        PageVO<SysProjectAuthVO> proxy = PageProxy.proxy(sysProjectAuthMapper::selectForPage, pageDTO);
        List<SysProjectAuthVO> records = proxy.getRecords();
        records.forEach(s -> {
            //检查每项的时间是否过期，如果过期将is_overdue设置成已过期
            boolean isEffect = true;
            //两个都不能为空，再判断是否在当前时间内，如果在时间内就不管下面，不在时间为否，修改状态为1
            if (!StringUtils.isEmpty(s.getAuthStartTime()) && !StringUtils.isEmpty(s.getAuthEndTime())) {
                isEffect = DateUtils.isBetweenDate(new Date(), s.getAuthStartTime(), s.getAuthEndTime());
            }
            //考虑两个时间都大于当前时间的情况；
            if (s.getAuthStartTime().after(new Date()) || s.getAuthEndTime().before(new Date())) {
                isEffect = true;
            }
            if (!isEffect) {
                SysProjectAuth sysProjectAuth = new SysProjectAuth();
                sysProjectAuth.setIsOverdue(true);
                sysProjectAuth.setId(s.getId());
                s.setIsOverdue(true);
                sysProjectAuthMapper.updateById(sysProjectAuth);
            }
        });
        proxy.setRecords(records);
        return proxy;
    }

    @Override
    public SysProjectAuthVO getAuthTenantById(Long id) {
        return sysProjectAuthMapper.getAuthTenantById(id);
    }

    /**
     * 项目授权（单个以及多个授权接口）
     */
    @Override
    public List<SysProjectAuth> authTenant(String projectList, SysProjectAuth sysProjectAuth) {
        Date startTime = sysProjectAuth.getAuthStartTime();
        Date endTime = sysProjectAuth.getAuthEndTime();
        if (endTime.before(startTime)) {
            throw new ServiceException("时间填写不正确，开始日期大于截止日期");
        }
        List<SysProjectAuth> sysProjectAuthList = new ArrayList<>();
        String[] split = checkTime(projectList, sysProjectAuth);
        checkDate(split, sysProjectAuthList, startTime, endTime, sysProjectAuth);
        sysProjectAuthMapper.insertList(sysProjectAuthList);
        return sysProjectAuthList;
    }

    /**
     * 更新权限的方式是删除当前选中的id集合，然后再重新添加（这个方式当时是为了批量添加）
     *
     * @param ids            权限集合，用逗号隔开
     * @param projectIds     项目id的字符串，用逗号隔开
     * @param sysProjectAuth 前端传来的对象（包括授权的前后时间点）
     */
    @Override
    public List<SysProjectAuth> updateAuthTenant(String ids, String projectIds, SysProjectAuth sysProjectAuth) {
        //这里是获取前端定义的授权时间区间值
        Date startTime = sysProjectAuth.getAuthStartTime();
        Date endTime = sysProjectAuth.getAuthEndTime();
        String[] auths = ids.split(",");
        List<Long> idList = new ArrayList<>();
        Arrays.stream(auths).forEach(s -> {
            Long id = Long.valueOf(s);
            idList.add(id);
        });
        sysProjectAuthMapper.deleteBatchIds(idList);
        String[] split = checkTime(projectIds, sysProjectAuth);
        List<SysProjectAuth> sysProjectAuthList = new ArrayList<>();
        checkDate(split, sysProjectAuthList, startTime, endTime, sysProjectAuth);
        sysProjectAuthList.forEach(s -> {
            s.setUpdateTime(new Date());
        });
        sysProjectAuthService.saveBatch(sysProjectAuthList);
        return sysProjectAuthList;
    }

    /**
     * 校验开始时间和结束时间的合理性
     *
     * @param projectList    项目id的字符串，用逗号隔开
     * @param sysProjectAuth 前端传来的对象（包括授权的前后时间点）
     */
    public String[] checkTime(String projectList, SysProjectAuth sysProjectAuth) {
        Date startTime = sysProjectAuth.getAuthStartTime();
        Date endTime = sysProjectAuth.getAuthEndTime();
        if (endTime.before(startTime)) {
            throw new ServiceException("时间填写不正确，开始日期大于截止日期");
        }
        return projectList.split(",");
    }

    /**
     * 校验同项目下的授权租户的时间是否重合，并加入集合
     */
    public void checkDate(String[] split, List<SysProjectAuth> sysProjectAuthList,
                          Date startTime, Date endTime, SysProjectAuth sysProjectAuth) {
        for (String s : split) {
            Long projectId = Long.valueOf(s);
            //对每个项目id进行校验
            List<SysProjectAuth> projectAuthList = sysProjectAuthMapper.selectList(
                    new LambdaQueryWrapper<SysProjectAuth>()
                            .eq(SysProjectAuth::getProjectId, projectId)
                            .eq(SysProjectAuth::getIsOverdue, true));
            projectAuthList.forEach(x -> {
                if (!(StringUtils.isEmpty(x.getAuthStartTime()) || StringUtils.isEmpty(x.getAuthEndTime()))) {
                    boolean isStart = DateUtils.isBetweenDate(startTime, x.getAuthStartTime(), x.getAuthEndTime());
                    boolean isEnd = DateUtils.isBetweenDate(endTime, x.getAuthStartTime(), x.getAuthEndTime());
                    if (isStart || isEnd) {
                        String proName = baseMapper.selectOne(new LambdaQueryWrapper<SysProject>()
                                .eq(SysProject::getId, x.getProjectId())
                        ).getName();
                        throw new ServiceException(proName + "项目的授权期与现有的有效的授权期存在重叠，请检查确认后提交");
                    }
                }
            });
            SysProjectAuth projectAuth = new SysProjectAuth();
            BeanUtils.copyProperties(sysProjectAuth, projectAuth);
            projectAuth.setProjectId(projectId);
            projectAuth.setAuthEndTime(endTime);
            projectAuth.setCreateTime(new Date());
            projectAuth.setAuthStartTime(startTime);
            projectAuth.setUpdateBy(AuthUtil.getCurrentUserId());
            projectAuth.setTenantId(sysProjectAuth.getTenantId());
            projectAuth.setIsOverdue(sysProjectAuth.getIsOverdue());
            sysProjectAuthList.add(projectAuth);
        }
    }

    /**
     * 多项目授权校验
     * <p>
     * projectList项目id的集合（例如：1，2，3，4....）
     */
    @Override
    public String checkTenant(String projectList, Long tenantId) {
        StringBuffer sb = new StringBuffer();
        Arrays.stream(projectList.split(",")).forEach(s -> {
            Long projectId = Long.valueOf(s);
            List<SysProjectAuth> sysProjectAuthList = sysProjectAuthMapper.selectList(
                    new LambdaQueryWrapper<SysProjectAuth>()
                            .eq(SysProjectAuth::getProjectId, projectId)
            );
            Set<Long> collect = sysProjectAuthList.stream().map(SysProjectAuth::getTenantId).collect(Collectors.toSet());
            List<Long> list = new ArrayList<>();
            if (collect.size() > 0) {
                collect.forEach(x -> {
                    if (!x.equals(tenantId)) {
                        list.add(x);
                    }
                });
            }
            if (list.size() > 0) {
                String projectName = baseMapper.selectNameById(projectId);
                if (sysProjectAuthList.size() > 0) {
                    sb.append(projectName).append(",");
                }
            }
        });
        if ("".equals(sb.toString())) {
            return "0";
        }
        String s = sb.toString();
        return s.substring(0, s.length() - 1);
    }

    public SysProject packSysProject(SysProjectDTO entity) {
        SysProject sysProject = new SysProject();
        sysProject.setId(entity.getId());
        sysProject.setTenantId(entity.getTenantId());
        sysProject.setCode(entity.getProCode());
        sysProject.setEnabled(entity.getEnabled());
        //业态的设置，后期需要转换成value值
        sysProject.setTradeType(entity.getTradeType());
        sysProject.setName(entity.getProName());
        sysProject.setStartTime(entity.getStartTime());
        sysProject.setRadius(entity.getRadius());
        sysProject.setOutCode(entity.getOutCode());
        sysProject.setHandTime(entity.getHandTime());
        sysProject.setLongitude(entity.getLongitude());
        sysProject.setLatitude(entity.getLatitude());
        sysProject.setRemark(entity.getRemark());
        return sysProject;
    }

    public SysProjectDetail packSysProjectDetail(SysProjectDTO entity) {
        SysProjectDetail sysProjectDetail = new SysProjectDetail();
        sysProjectDetail.setProjectId(entity.getId());
        sysProjectDetail.setCity(entity.getCity());
        sysProjectDetail.setBuildArea(entity.getBuildArea());
        sysProjectDetail.setBuildDate(entity.getBuildDate());
        sysProjectDetail.setProLogo(entity.getProLogo());
        sysProjectDetail.setProImage(entity.getProImage());
        sysProjectDetail.setProDistributePic(entity.getProDistributePic());
        sysProjectDetail.setControlBuildArea(entity.getControlBuildArea());
        sysProjectDetail.setUsableArea(entity.getUsableArea());
        sysProjectDetail.setFloorAreaRatio(entity.getFloorAreaRatio());
        return sysProjectDetail;
    }

}
